package com.night.icm.service.business.service;

import com.night.icm.common.exception.NoSuchDataException;
import com.night.icm.common.jpa.PageHelper;
import com.night.icm.common.service.PageDataUtil;
import com.night.icm.common.utils.PageDataDTO;
import com.night.icm.model.business.StudentCreditRecordDTO;
import com.night.icm.persistence.base.entity.Academy;
import com.night.icm.persistence.base.entity.Class;
import com.night.icm.persistence.base.entity.Profession;
import com.night.icm.persistence.base.entity.Student;
import com.night.icm.persistence.business.entity.AcademicProgress;
import com.night.icm.persistence.business.entity.StudentCreditRecord;
import com.night.icm.persistence.business.entity.SystemFile;
import com.night.icm.persistence.business.reporsitory.StudentCreditRecordRepository;
import com.night.icm.persistence.business.reporsitory.SystemFileRepository;
import com.night.icm.service.business.mapper.StudentCreditRecordMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * StudentCreditRecordServiceImpl
 *
 * @author Liao ZhiYong
 * @date 2020/3/22
 */
@Slf4j
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class StudentCreditRecordServiceImpl implements StudentCreditRecordService {

    private final SystemFileRepository systemFileRepository;
    private StudentCreditRecordMapper studentCreditRecordMapper;
    private StudentCreditRecordRepository studentCreditRecordRepository;

    @Autowired
    public StudentCreditRecordServiceImpl(StudentCreditRecordMapper studentCreditRecordMapper, StudentCreditRecordRepository studentCreditRecordRepository, SystemFileRepository systemFileRepository) {
        this.studentCreditRecordMapper = studentCreditRecordMapper;
        this.studentCreditRecordRepository = studentCreditRecordRepository;
        this.systemFileRepository = systemFileRepository;
    }

    /**
     * 根据学生学号查找学生学分记录
     *
     * @param studentCode 学生code
     * @return 学生学分记录
     */
    @Override
    public StudentCreditRecordDTO findByStudentCode(String studentCode) {
        StudentCreditRecord studentCreditRecord = this.studentCreditRecordRepository.findByStudentCode(studentCode);
        return this.studentCreditRecordMapper.toDTO(studentCreditRecord);
    }

    /**
     * 通过id查找学生学分记录
     *
     * @param id id
     * @return 学生学分记录
     */
    @Override
    public StudentCreditRecordDTO findById(String id) {
        Optional<StudentCreditRecord> byId = this.studentCreditRecordRepository.findById(Long.valueOf(id));
        if (!byId.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return this.studentCreditRecordMapper.toDTO(byId.get());
    }

    /**
     * 提交学生学分记录
     *
     * @param id                     id
     * @param studentCreditRecordDTO 学生学分记录
     * @return 学生学分记录
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public StudentCreditRecordDTO complete(String id, StudentCreditRecordDTO studentCreditRecordDTO) {
        Optional<StudentCreditRecord> optional = this.studentCreditRecordRepository.findById(Long.valueOf(id));
        if (!optional.isPresent()) {
            throw new NoSuchDataException(id);
        }
        StudentCreditRecord studentCreditRecord = optional.get();
        studentCreditRecordDTO.setTotal(studentCreditRecord.getTotal() - studentCreditRecord.getInnovationScore() + studentCreditRecordDTO.getInnovationScore());
        this.studentCreditRecordMapper.updateEntity(studentCreditRecordDTO, studentCreditRecord);

        // 删除原有附件
        studentCreditRecord.setFiles(null);
        this.studentCreditRecordRepository.save(studentCreditRecord);
        // 更新附件
        List<String> fileIds = studentCreditRecordDTO.getFileIds();
        saveFiles(studentCreditRecord, fileIds);
        this.studentCreditRecordRepository.save(studentCreditRecord);
        return this.studentCreditRecordMapper.toDTO(studentCreditRecord);
    }

    /**
     * 分页查找学生学分记录
     *
     * @param page         页号，从0开始
     * @param size         每页记录条数
     * @param sort         排序字段，例如：字段1,asc,字段2,desc
     * @param academyId    学院名称
     * @param professionId 专业名称
     * @param classId      班级名称
     * @param studentName  学生姓名
     * @param grade        所属年级
     * @return 学生学分记录
     */
    @Override
    public PageDataDTO<StudentCreditRecordDTO> findOnePage(int page, int size, String sort, String academyId, String professionId, String classId, String studentName, String grade) {
        Specification<StudentCreditRecord> specification = ((Root<StudentCreditRecord> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            List<Predicate> conditions = new ArrayList<>();
            if (!StringUtils.isAllBlank(academyId, professionId, classId, studentName) || grade != null) {
                if (grade != null) {
                    conditions.add(cb.and(cb.equal(root.get("grade").as(Integer.class), Integer.valueOf(grade))));
                }
                Join<StudentCreditRecord, AcademicProgress> academicProgressJoin = root.join("academicProgress", JoinType.LEFT);
                Join<AcademicProgress, Student> studentJoin = academicProgressJoin.join("student", JoinType.LEFT);
                Join<Student, Academy> academyJoin = studentJoin.join("academy", JoinType.LEFT);
                Join<Student, Profession> professionJoin = studentJoin.join("profession", JoinType.LEFT);
                Join<Student, Class> classJoin = studentJoin.join("aClass", JoinType.LEFT);
                if (StringUtils.isNotBlank(academyId)) {
                    conditions.add(cb.and(cb.equal(academyJoin.get("id").as(Long.class), Long.valueOf(academyId))));
                }
                if (StringUtils.isNotBlank(professionId)) {
                    conditions.add(cb.and(cb.equal(professionJoin.get("id").as(Long.class), Long.valueOf(professionId))));
                }
                if (StringUtils.isNotBlank(classId)) {
                    conditions.add(cb.and(cb.equal(classJoin.get("id").as(Long.class), Long.valueOf(classId))));
                }
                if (StringUtils.isNotBlank(studentName)) {
                    conditions.add(cb.and(cb.like(root.get("studentName").as(String.class), "%" + studentName + "%")));
                }
            }
            if (!conditions.isEmpty()) {
                query.where(conditions.toArray(new Predicate[0]));
            }
            return null;
        });
        Page<StudentCreditRecord> all = this.studentCreditRecordRepository.findAll(specification, PageHelper.generatePageRequest(page, size, sort));
        List<StudentCreditRecordDTO> list = this.studentCreditRecordMapper.toList(all.getContent());
        return PageDataUtil.toPageData(all, list);
    }

    /**
     * 保存文件
     *
     * @param studentCreditRecord 对象
     * @param fileIds             文件id数组
     */
    private void saveFiles(StudentCreditRecord studentCreditRecord, List<String> fileIds) {
        if (null != fileIds && !fileIds.isEmpty()) {
            List<Long> ids = new ArrayList<>();
            fileIds.forEach(id -> ids.add(Long.parseLong(id)));
            List<SystemFile> files = this.systemFileRepository.findAllById(ids);
            studentCreditRecord.setFiles(files);
        }
    }
}